package com.atguigu.exam.service.impl;

import com.atguigu.exam.entity.Category;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.mapper.CategoryMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.CategoryService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper,Category> implements CategoryService {
    @Autowired
    private QuestionMapper questionMapper;
    /**
     * 查询所有分类的分类的题目数量
     * @return 分类+count
     */
    @Override
    public List<Category> getCategoryList() {
        //1.查询所有分类信息
        List<Category> categoryList = list();
        //2.为分类列表填充题目数量
        fillQuestionCount(categoryList);
        return categoryList;
    }

    /**
     * 查询树状分类集合
     * @return 分类+count+child
     */
    @Override
    public List<Category> getCategoryTreeList() {
        //1.查询所有分类信息
        List<Category> categoryList = list();
        //2.为分类列表填充题目数量
        fillQuestionCount(categoryList);
        //3.给所有分类根据parent_id进行分组
        Map<Long, List<Category>> parentIdMap = categoryList.stream().collect(Collectors.groupingBy(Category::getParentId));
        //4.筛选原来分类集合中parent_id=0
        List<Category> categoryListResult = categoryList.stream().filter(category -> category.getParentId() == 0).collect(Collectors.toList());
            //5.对筛选后的集合进行循环
            categoryListResult.forEach(category -> {
                //赋值子分类
                List<Category> childCategoryList = parentIdMap.getOrDefault(category.getId(), new ArrayList<>());
                childCategoryList.sort((o1, o2) -> o1.getSort()-o2.getSort());
                category.setChildren(childCategoryList);
                //赋值count = 当前count+子分类的count
                long childCount = childCategoryList.stream().mapToLong(Category::getCount).sum();
                category.setCount(category.getCount()+childCount);
            });
        //6.返回分类集合
        return categoryListResult;
    }

    /**
     * 按照分类信息进行题目数量填充
     * 1.判断分类集合是否为空
     * 2.查询所有分类和分类对应的题目数量
     * 3.进行分类数据和count转化，map<categoryId,count>
     * 4.给集合分类，查询count，并赋值
     * */
    private void fillQuestionCount(List<Category> categoryList){
        //1.判断分类集合是否为空
        if(categoryList == null|| categoryList.isEmpty()){
            throw new RuntimeException("查询分类集合为空");
        }
        //2.查询所有分类和分类对应的题目数量
        List<Map<Long,Long>> mapList = questionMapper.selectCategoryCount();
        Map<Long,Long> resultCount = mapList.stream()
                .collect(Collectors.toMap(
                        m -> m.get("category_id"),
                        m->m.get("count")
                ));
        //3.进行分类结果填充
        categoryList.forEach(category -> {
            category.setCount(resultCount.getOrDefault(category.getId(),0L));
        });
    }

    /**
     * 新增分类（二级分类）
     * @param category
     */
    @Override
    public void saveCategory(Category category) {
        //1.同一个父分类下不能出现同名的子分类
        //通过实体类接收的参数判断同一个父类下有没有同名的子类
        //select count(1) from categories where parent_id = category.getParentId()
        // and name = category.getName()
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Category::getParentId,category.getParentId());
        lambdaQueryWrapper.eq(Category::getName,category.getName());
        //如果count(1)>0则说明父分类下有同名子分类
        long count = count(lambdaQueryWrapper);
        if (count>0){
            Category parent = getById(category.getParentId());
            throw new RuntimeException("在%s父分类下，已存在名为%s的子分类，本次添加失败".formatted(parent.getName(),category.getName()));
        }
        //2.插入新的子分类
        save(category);
    }

    /**
     * 更新分类信息
     * @param category
     */
    @Override
    public void updateCategory(Category category) {
        /**
         * {
         *   "id": 16, // 必须提供要更新的分类ID
         *   "name": "微服务技术",
         *   "parentId": 3,
         *   "sort": 6
         * }
         * 对已存在的子分类进行更新操作
         * 更改分子类名称：1.如果子分类名称没有改变，保存（更新）成功
         *              2.如果子分类名称发生改变，查询同一父分类下是否有相同的子分类名称
         *                2.1如果有相同的子分类名称，则保存（更新）失败
         *                2.2如果没有相同的子分类名称，则保存（更新）成功
         * 例：把子分类git改为Java基础，如果COUNT(1)>0，则更新失败
         * SELECT COUNT(1) FROM categories
         * WHERE parent_id = 13(category.getParentId) AND name = 'Java基础'(category.getName)
         * AND id <> 30(category.getId)
         * */
        //1.先校验，拼接条件
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Category::getParentId,category.getParentId());
        lambdaQueryWrapper.eq(Category::getName,category.getName());
        lambdaQueryWrapper.ne(Category::getId,category.getId());
        long count = count(lambdaQueryWrapper);
        if(count>0){
            //同一个父类下有相同的子分类，更新失败
            Category parent = getById(category.getParentId());
            throw new RuntimeException("在父分类%s下，已存在名为%s的子分类，本次更新失败".formatted(parent.getName(),category.getName()));
        }
        //2.保存更新的信息
        updateById(category);
    }

    /**
     * 删除分类信息
     * @param id
     * 删除前必须进行检查，二级分类下没有题目才能删除该二级分类
     */
    @Override
    public void removeCategoryById(Long id) {
        //1.检查是否是一级分类，一级分类不能删除
        Category category = getById(id);
        if (category.getParentId()==0){
            throw new RuntimeException("不能删除一级分类");
        }
        //2.检查二级分类下是否有题目
        LambdaQueryWrapper<Question> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Question::getCategoryId,id);
        Long count = questionMapper.selectCount(lambdaQueryWrapper);
        if (count>0){
            throw new RuntimeException("当前%s分类下存在%s道题目，无法删除该二级分类".formatted(category.getName(),count));
        }
        //3.删除二级分类
        removeById(id);
    }
}